package cuppics;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.junit.Test;

public class Prj24 {

	/**
	 * A permutation is an ordered arrangement of objects. For example, 3124 is
	 * one possible permutation of the digits 1, 2, 3 and 4. If all of the
	 * permutations are listed numerically or alphabetically, we call it
	 * lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
	 * 
	 * 012 021 102 120 201 210
	 * 
	 * What is the millionth lexicographic permutation of the digits 0, 1, 2, 3,
	 * 4, 5, 6, 7, 8 and 9?
	 */
	@Test
	public void test() {
		System.out.println(Calculator.calculate(1000000));
		System.out.println(9 * 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1);
	}

	public static class Calculator {

		public static String calculate(int upLimit) {

			Set<Integer> set = new HashSet<Integer>();
			int[] arr = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
			for (int val : arr) {
				set.add(val);
			}

			int[] outArr = new int[10];
			nextPermutation(upLimit, set, outArr);
			return arr2Str(outArr);
		}

		public static void nextPermutation(int num, Set<Integer> dataSet,
				int[] outArr) {

			int limit = num;
			int count = outArr.length;
			for (int i = 0; i < count; i++) {
				int size = getN(dataSet.size() - 1);

				int j = 0;
				for (; j < dataSet.size() - 1; j++) {

					if (j * size <= limit && (j + 1) * size > limit) {
						break;
					}
				}
				outArr[i] = getMax(dataSet, j);

				dataSet = removeSetByVal(dataSet, outArr[i]);

				limit -= j * size;

				if (limit == 0) {

					List<Integer> tmp = new ArrayList<Integer>();
					tmp.addAll(dataSet);
					Collections.sort(tmp);

					for (int k = i + 1; k < outArr.length; k++) {
						outArr[k] = tmp.get(tmp.size() - 1 - (k - i - 1));
					}

					return;
				}
			}

		}

		private static String arr2Str(int[] val) {
			StringBuffer sb = new StringBuffer();
			for (int iv : val) {
				sb.append(iv);
			}

			return sb.toString();
		}

		
		@Deprecated
		private static String arr2Str(List<Integer> val) {
			StringBuffer sb = new StringBuffer();
			for (int iv : val) {
				sb.append(iv);
			}

			return sb.toString();
		}

		@Deprecated
		private static void iterSet(Set<Integer> dataSet, List<Integer> arr,
				int limit, int index) {

			if (limit == 0) {
				return;
			}

			int size = getN(dataSet.size() - 1);
			int i = 0;
			for (; i < dataSet.size() - 1; i++) {

				if (i * size <= limit && (i + 1) * size > limit) {
					break;
				}
			}
			arr.add(getMax(dataSet, i));

			Set<Integer> setRemoveThisNum = removeSetByVal(dataSet,
					arr.get(index));
			List<Integer> nextIterArrCopy = copyList(arr);
			iterSet(setRemoveThisNum, nextIterArrCopy, limit - i * size,
					index + 1);

			arr = copyList(nextIterArrCopy);

		}

		private static List<Integer> copyList(List<Integer> arr) {

			List<Integer> ret = new ArrayList<Integer>();
			for (int i = 0; i < arr.size(); i++) {
				ret.add(arr.get(i));
			}
			return ret;
		}

		private static Set<Integer> removeSetByVal(Set<Integer> dataSet, int val) {

			Set<Integer> ret = new HashSet<Integer>(dataSet);
			ret.remove(val);
			return ret;

		}

		private static int getMax(Set<Integer> dataSet, int id) {

			List<Integer> data = new ArrayList<Integer>();
			data.addAll(dataSet);
			Collections.sort(data);
			return data.get(id);
		}

		public static int getN(int num) {
			int sum = 1;
			for (int i = 0; i < num; i++) {
				sum *= (i + 1);
			}
			return sum;
		}

	}

}
